home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CPPTASK.ARJ / TSKSIO.CPP < prev    next >
C/C++ Source or Header  |  1991-08-21  |  22KB  |  882 lines

  1. /*
  2.    CPPTask - A Multitasking Kernel For C++
  3.  
  4.    Version 1.0 08-12-91
  5.  
  6.    Ported by Rich Smith from:
  7.  
  8.    Public Domain Software written by
  9.       Thomas Wagner
  10.       Patschkauer Weg 31
  11.       D-1000 Berlin 33
  12.       West Germany
  13.  
  14.    TSKSIO.CPP - Serial I/O interface routines.
  15.  
  16.    Subroutines:
  17.       sioint3
  18.       sioint4
  19.       commport::chng_rts
  20.       commport::transmit_ready
  21.       commport::modem_status_int
  22.       commport::receive_ready
  23.       commport::sioint
  24.       commport::commport
  25.       commport::~commport
  26.       commport::change_rts
  27.       commport::change_dtr
  28.       commport::change_baud
  29.       commport::change_parity
  30.       commport::change_wordlength
  31.       commport::change_stopbits
  32.       commport::watch_modem
  33.       commport::protocol
  34.       commport::send
  35.       commport::receive
  36.       commport::rcv_overrun
  37.       commport::check
  38.       commport::modem_status
  39.       commport::complete
  40.       commport::wait_complete
  41.       commport::flush_receive
  42.  
  43.    The tables used are:
  44.  
  45.       port_list   The pointer to the list of defined ports. Newly
  46.                   defined ports are added to the end of the list.
  47.                   Ports can never be deleted. Each port descriptor
  48.                   contains the hardware info for the port, plus a
  49.                   pointer to the associated sio-control-block if the
  50.                   port was initialized.
  51.                   
  52.       port_last   The pointer to the last element in port_list.
  53.  
  54.       irq_array   Is an array of pointers to sio-control-blocks. For
  55.                   each possible IRQ-line the entry in this table points
  56.                   to the first block active for this line. If the IRQ
  57.                   is shared, sio-blocks are chained into this list via 
  58.                   their "next" pointer.
  59.  
  60.       irq_procs   Contains the pointer to the interrupt handler function
  61.                   for the corresponding IRQ-line.
  62.  
  63.       port_descr  Contains the statically defined port descriptor blocks.
  64.  
  65.    NOTE:    You can not dynamically define ports for IRQ-lines that
  66.             have no interrupt handler function defined. To be completely
  67.             flexible, you would have to define sioint-handlers for all
  68.             possible IRQs and enter the addresses into the irq_procs array.
  69.  
  70.    CAUTION: Please restrict the installation and removal of comm-
  71.             ports to *one* task. The manipulation of the lists is
  72.             not protected, so simultaneous install/remove calls
  73.             may cause trouble. Since ports are normally installed and
  74.             removed in the main task, the protection of critical regions
  75.             seemed unnecessary.
  76.  
  77.    CAUTION: Shared interrupt logic and IRQ-lines above 4 were not
  78.             tested due to the lack of suitable hardware. Changes may
  79.             be necessary in the handling of the modem control register
  80.             OUT2 line that normally controls interrupt enable, depending
  81.             on the multiport-hardware installed in the target system.
  82.  
  83. */
  84.  
  85. #include "task.hpp"
  86. #include "sio.hpp"
  87.  
  88. #define MAX_IRQ   16    /* Maximum number of interrupt lines, 
  89.                            16 for AT, 8 for XT. Can be left at 16 */
  90.  
  91. #define CHAIN_IRQBIT    0x04  /* Chained int controller IRQ bit */
  92.  
  93. #define RESTORE_DEFAULT 1     /* Restore parameter for remove_all */
  94.  
  95. #define RTS       0x02
  96. #define DTR       0x01
  97. #define OUT2      0x08
  98.  
  99. #define ERR_MASK  0x1e
  100.  
  101. #define inta00    0x20   /* 8259 interrupt controller control-port */
  102. #define inta01    0x21   /* 8259 interrupt controller mask-port */
  103.  
  104. #define inta10    0xa0   /* secondary 8259 control-port for IRQ 8-15 */
  105. #define inta11    0xa1   /* secondary 8259 mask-port for IRQ 8-15 */
  106.  
  107. #define rdserv    0x0b   /* read service register control value */
  108. #define eoi       0x20   /* end of interrupt signal for 8259 */
  109.  
  110. #define intdata   0x0b   /* Enable Interrupts except Line status */
  111.  
  112. #define rxreadybit 0x01
  113. #define txemptybit 0x40
  114. #define txreadybit 0x20
  115. #define framingbit 0x08
  116. #define breakbit   0x10
  117.  
  118. /* Note: In version 1.1, port offsets start at 0, not 8 */
  119.  
  120. #define linecontrol  0x03
  121. #define linestatus   0x05
  122. #define intid        0x02
  123. #define intenable    0x01
  124. #define modemcontrol 0x04
  125. #define modemstatus  0x06
  126. #define receivedata  0x00
  127. #define transmitdata 0x00
  128.  
  129. #define baudreg_dll  0x00     /* baud rate least significant byte */
  130. #define baudreg_dlm  0x01     /* baud rate most significant byte */
  131.  
  132. /*
  133.    Default values for initialising the ports.
  134.    Change to your liking (but remember that OUT2 must be set in the
  135.    modem control register to allow interrupts to come through with 
  136.    normal controllers).
  137. */
  138.  
  139. #define dflt_modcon 0x0b   /* Modem Control: Activate DTR, RTS, OUT2 */
  140. #define dflt_baud   96     /* Baud Rate Divisor: 1200 Baud */
  141. #define dflt_lcon   0x03   /* Line Control: No Parity, 1 Stop, 8 Data */
  142.  
  143. /*
  144.    Defined baud rates. You may expand this table with non-standard
  145.    rates if desired.
  146. */
  147.  
  148. local long baud_table [] = {
  149.                                50L, 2304L,
  150.                                75L, 1536L,
  151.                               110L, 1047L,
  152.                               134L,  857L,
  153.                               150L,  768L,
  154.                               300L,  384L,
  155.                               600L,  192L,
  156.                              1200L,   96L,
  157.                              1800L,   64L,
  158.                              2000L,   58L,
  159.                              2400L,   48L,
  160.                              3600L,   32L,
  161.                              4800L,   24L,
  162.                              7200L,   16L,
  163.                              9600L,   12L,
  164.                             19200L,    6L,
  165.                             38400L,    3L,
  166.                                 0L,    0L };
  167.  
  168. local byte force_transmit_ready;       /* flag to indicate
  169.                                           transmitter needs service */
  170.  
  171. /*-------------------------------------------------------------------------*/
  172.  
  173. /*
  174.    To add static support for other COM-Ports, define
  175.       - Port base
  176.       - IRQ-Line
  177.       - Interrupt vector
  178.    here, and add the necessary data to the port_descr array.
  179.    If the port does *not* share an IRQ with the predefined ports,
  180.    define the corresponding interrupt function by duplicating siointx,
  181.    and place the entry for this function into the irq_procs array.
  182.  
  183. */
  184.  
  185. #define STATIC_PORTS  2       /* Number of statically defined ports */
  186.  
  187. /* Note: In version 1.1, port offsets start at 0, not 8 */
  188.  
  189. #define com1_base    0x3f8    /* COM1 port base */
  190. #define com2_base    0x2f8    /* COM2 port base */
  191.  
  192. #define com1_irq     4        /* IRQ-Line for COM1 */
  193. #define com2_irq     3        /* IRQ-Line for COM2 */
  194.  
  195. #define com1_vect    0x0c     /* Interrupt vector for COM1 */
  196. #define com2_vect    0x0b     /* Interrupt vector for COM2 */
  197.  
  198. /*-------------------------------------------------------------------------*/
  199.  
  200.  
  201. typedef void (interrupt far * intprocptr)(void);
  202.  
  203. void interrupt far sioint3 (void);
  204. void interrupt far sioint4 (void);
  205.  
  206. /* 
  207.    Table of Interrupt handler functions for each IRQ line.
  208. */
  209.  
  210. local intprocptr irq_procs [MAX_IRQ] = {  NULL,    /* IRQ 0 */
  211.                                           NULL,    /* IRQ 1 */
  212.                                           NULL,    /* IRQ 2 */
  213.                                           (intprocptr)sioint3, /* IRQ 3 */
  214.                                           (intprocptr)sioint4, /* IRQ 4 */
  215.                                           NULL,    /* IRQ 5 */
  216.                                           NULL,    /* IRQ 6 */
  217.                                           NULL,    /* IRQ 7 */
  218.                                           NULL,    /* IRQ 8 */
  219.                                           NULL,    /* IRQ 9 */
  220.                                           NULL,    /* IRQ 10 */
  221.                                           NULL,    /* IRQ 11 */
  222.                                           NULL,    /* IRQ 12 */
  223.                                           NULL,    /* IRQ 13 */
  224.                                           NULL,    /* IRQ 14 */
  225.                                           NULL };  /* IRQ 15 */
  226.  
  227.  
  228. /* When adding entries to port_descr, be sure to chain the 
  229.    elements in ascending order via the first field, and to
  230.    increase the internal port number in the second field. */
  231.  
  232. local port_data port_descr [STATIC_PORTS] = {
  233.      { &port_descr[1], 0, NULL, com1_base, com1_irq, com1_vect },
  234.      { NULL,           1, NULL, com2_base, com2_irq, com2_vect }
  235. };
  236.  
  237. local commptr irq_array [MAX_IRQ] = { NULL };
  238.  
  239. local portptr port_list = &port_descr [0];
  240. local portptr port_last = &port_descr [1];
  241.  
  242. local int ports = STATIC_PORTS;
  243.  
  244. extern funcptr v24_remove_func;
  245.  
  246. /*-------------------------------------------------------------------------*/
  247.  
  248.  
  249. void commport::chng_rts (int on)
  250. {
  251.    rtsoff = (byte)(!on);
  252.    cmodcontrol = (cmodcontrol & ~RTS) | ((on) ? RTS : 0);
  253.    tsk_outp (port_base + modemcontrol, cmodcontrol);
  254. }
  255.  
  256.  
  257. void commport::transmit_ready (void)
  258. {
  259.    int i;
  260.  
  261.    force_transmit_ready = 0;
  262.  
  263.    if ((i = r_xoff) < 0)
  264.       {
  265.       tsk_outp (port_base + transmitdata, (i == -1) ? XOFF : XON);
  266.       r_xoff = (i == -1) ? 1 : 0;
  267.       xmit_pending = 1;
  268.       return;
  269.       }
  270.  
  271.    xmit_pending = 0;
  272.  
  273.    if (!(wait_xmit = (byte)(xmit_pipe.check_pipe () != -1)))
  274.       return;
  275.  
  276.    if ((modem_flags & modstat) ^ modem_flags)
  277.       return;
  278.  
  279.    if (flags & XONXOFF && t_xoff)
  280.       return;
  281.  
  282.    wait_xmit = 0;
  283.  
  284.    if ((i = xmit_pipe.c_read_pipe ()) < 0)
  285.       return;
  286.  
  287.    tsk_outp (port_base + transmitdata, (byte)i);
  288.    xmit_pending = 1;
  289. }
  290.  
  291.  
  292. void commport::modem_status_int (void)
  293. {
  294.    modstat = tsk_inp (port_base + modemstatus);
  295.  
  296.    if (wait_xmit)
  297.       transmit_ready ();
  298. }
  299.  
  300.  
  301. void commport::receive_ready (void)
  302. {
  303.    word status;
  304.    word ch;
  305.  
  306.    while ((status = tsk_inp (port_base + linestatus)) & rxreadybit)
  307.       {
  308.       /* Correct for possible loss of transmit interrupt from IIR register */   
  309.       if (status & txreadybit)
  310.           force_transmit_ready = 1;
  311.  
  312.       tsk_nop ();
  313.       ch = tsk_inp (port_base + receivedata);
  314.  
  315.       if (flags & XONXOFF)
  316.          {
  317.          if (ch == XON)
  318.             {
  319.             t_xoff = 0;
  320.             if (wait_xmit)
  321.                transmit_ready ();
  322.             continue;
  323.             }
  324.          else if (ch == XOFF)
  325.             {
  326.             t_xoff = 1;
  327.             continue;
  328.             }
  329.          if (!r_xoff &&
  330.              rcv_pipe.wpipe_free () < xoff_threshold)
  331.             {
  332.             r_xoff = -1;
  333.             if (!xmit_pending)
  334.                transmit_ready ();
  335.             }
  336.          }
  337.  
  338.       if (flags & RTSCTS && !rtsoff)
  339.          if (rcv_pipe.wpipe_free () < xoff_threshold)
  340.             chng_rts (0);
  341.  
  342.       status = (status & ERR_MASK) << 8;
  343.       if (rcv_pipe.c_write_wpipe (ch | status) < 0)
  344.          overrun = 1;
  345.       }
  346. }
  347.  
  348.  
  349. /*-------------------------------------------------------------------------*/
  350.  
  351.  
  352. void commport::sioint (void)
  353. {
  354.    int id;
  355.  
  356.    force_transmit_ready = 0;
  357.  
  358.    while (!((id = tsk_inp (port_base + intid)) & 1))
  359.       switch (id & 0x07)
  360.          {
  361.          case 0x00:  modem_status_int ();
  362.                      break;
  363.  
  364.          case 0x02:  transmit_ready ();
  365.                      break;
  366.  
  367.          case 0x04:  receive_ready ();
  368.                      break;
  369.  
  370. /*       case 0x06:  line_status_int (); (currently not used)
  371.                      break;
  372. */
  373.          }
  374.       if (force_transmit_ready)
  375.          transmit_ready ();
  376. }
  377.  
  378.  
  379. void interrupt far sioint3 (void)
  380. {
  381.    commptr curr;
  382.  
  383.    tsk_sti ();
  384.    for (curr = irq_array [3]; curr != NULL; curr = curr->next)
  385.       curr->sioint ();
  386.  
  387.    tsk_cli ();
  388.    /* NOTE: for IRQ's 8-15, add the following here:
  389.       tsk_outp (inta10, eoi);
  390.    */
  391.    tsk_outp (inta00, eoi);
  392. }
  393.  
  394.  
  395. void interrupt far sioint4 (void)
  396. {
  397.    commptr curr;
  398.  
  399.    tsk_sti ();
  400.    for (curr = irq_array [4]; curr != NULL; curr = curr->next)
  401.       curr->sioint ();
  402.  
  403.    tsk_cli ();
  404.    /* NOTE: for IRQ's 8-15, add the following here:
  405.       tsk_outp (inta10, eoi);
  406.    */
  407.    tsk_outp (inta00, eoi);
  408. }
  409.  
  410. /*-------------------------------------------------------------------------*/
  411.  
  412. commport::commport (int portnum, int init,
  413.                           farptr rcvbuf, word rcvsize,
  414.                           farptr xmitbuf, word xmitsize)
  415. :xmit_pipe(xmitbuf, xmitsize), rcv_pipe(rcvbuf, rcvsize)
  416. {
  417.    portptr portp;
  418.    int pbase;
  419.    intprocptr far *intptr;
  420.    int i, inta;
  421.  
  422.    if (port < 0 || !rcvsize || !xmitsize)
  423.       return;
  424.  
  425.    portp = port_list;
  426.  
  427.    if (portnum & 0x80)     /* Relative port number */
  428.       {
  429.       portnum &= 0x7f;
  430.       if (portnum > 4)
  431.          return;
  432.       pbase = *((wordptr)(MK_FP (0x40, portnum * 2)));
  433.       if (!pbase)
  434.          return;
  435.  
  436.       for (portnum = 0; portnum < ports; portnum++, portp = portp->next)
  437.          if (portp->base == pbase)
  438.             break;
  439.  
  440.       if (portnum >= ports)
  441.          return;
  442.       }
  443.    else 
  444.       {
  445.       if (portnum > ports)
  446.          return;
  447.       for (i = 0; i < portnum; i++)
  448.          portp = portp->next;
  449.       }
  450.  
  451.    if (portp->sio != NULL) /* Port already in use ? */
  452.       return;
  453.  
  454.    portp->sio = this;
  455.  
  456.    pbase = port_base = portp->base;
  457.    port = portp;
  458.  
  459.    /* Check if port accessible by modifying the modem control register */
  460.  
  461.    i = cmodcontrol = save_mcon = tsk_inp (pbase + modemcontrol);
  462.    if (i & 0xe0)
  463.       {
  464.       port->sio = NULL;
  465.       return;
  466.       }
  467.    tsk_nop ();
  468.    tsk_outp (pbase + modemcontrol, 0xe0 | i);
  469.    tsk_nop ();
  470.    if (tsk_inp (pbase + modemcontrol) != (byte) i)
  471.       {
  472.       port->sio = NULL;
  473.       return;
  474.       }
  475.  
  476.    /* Port seems OK */
  477.  
  478.    civect = portp->vector;
  479.    irqbit = (byte)(1 << (portp->irq & 0x07));
  480.  
  481.    wait_xmit = xmit_pending = 0;
  482.    overrun = 0;
  483.    flags = 0;
  484.    modem_flags = 0;
  485.    r_xoff = t_xoff = 0;
  486.    rtsoff = 0;
  487.    restore = 1;
  488.  
  489.    clcontrol = save_lcon = tsk_inp (pbase + linecontrol);
  490.    tsk_nop ();
  491.    save_inten = tsk_inp (pbase + intenable);
  492.    tsk_nop ();
  493.  
  494.    if (init)
  495.       {
  496.       clcontrol = dflt_lcon;
  497.       cmodcontrol = dflt_modcon;
  498.       }
  499.  
  500.    tsk_outp (pbase + linecontrol, clcontrol | 0x80);
  501.    tsk_nop ();
  502.    save_bd1 = tsk_inp (pbase + baudreg_dll);
  503.    tsk_nop ();
  504.    save_bd2 = tsk_inp (pbase + baudreg_dlm);
  505.    tsk_nop ();
  506.    tsk_outp (pbase + linecontrol, clcontrol);
  507.    tsk_nop ();
  508.  
  509.    tsk_outp (pbase + intenable, 0);
  510.  
  511.    if (irq_array [portp->irq] == NULL)
  512.       {
  513.       intptr = (intprocptr far *)MK_FP (0, civect * 4);
  514.       tsk_cli ();
  515.       savvect = *intptr;
  516.       *intptr = irq_procs [portp->irq];
  517.       tsk_sti ();
  518.       }
  519.  
  520.    if (init)
  521.       {
  522.       tsk_outp (pbase + linecontrol, dflt_lcon | 0x80);
  523.       tsk_nop ();
  524.       tsk_outp (pbase + baudreg_dll, dflt_baud);
  525.       tsk_nop ();
  526.       tsk_outp (pbase + baudreg_dlm, dflt_baud >> 8);
  527.       tsk_nop ();
  528.       tsk_outp (pbase + linecontrol, dflt_lcon);
  529.       tsk_nop ();
  530.       tsk_outp (pbase + modemcontrol, dflt_modcon);
  531.       tsk_nop ();
  532.       }
  533.    else
  534.       {
  535.       i = tsk_inp (pbase + modemcontrol) | OUT2;
  536.       tsk_nop ();
  537.       tsk_outp (pbase + modemcontrol, i);
  538.       tsk_nop ();
  539.       }
  540.  
  541.    while (tsk_inp (pbase + linestatus) & rxreadybit)
  542.       {
  543.       tsk_nop ();
  544.       tsk_inp (pbase + receivedata);
  545.       tsk_nop ();
  546.       }
  547.    tsk_nop ();
  548.  
  549.    tsk_inp (pbase + linestatus);
  550.    tsk_nop ();
  551.    modstat = tsk_inp (pbase + modemstatus);
  552.    tsk_nop ();
  553.    tsk_inp (pbase + intid);
  554.    tsk_nop ();
  555.  
  556.    inta = (portp->irq > 7) ? inta11 : inta01;
  557.  
  558.    if (irq_array [portp->irq] == NULL)
  559.       {
  560.       if (portp->irq > 7)
  561.          {
  562.          i = tsk_inp (inta01) & ~CHAIN_IRQBIT;
  563.          tsk_nop ();
  564.          tsk_outp (inta01, i);
  565.          }
  566.  
  567.       save_irq = (byte)((i = tsk_inp (inta)) & irqbit);
  568.       tsk_nop ();
  569.       tsk_outp (inta, i & ~irqbit);
  570.       }
  571.    else
  572.       save_irq = (irq_array [portp->irq])->save_irq;
  573.  
  574.    tsk_cli ();
  575.    next = irq_array [portp->irq];
  576.    irq_array [portp->irq] = this;
  577.    tsk_sti ();
  578.  
  579.    /* Enable interrupts with correction for possible loss of the 
  580.       first tranmit interrupt on INS8250 and INS8250-B chips */
  581.    for (;;)
  582.        {
  583.        if (tsk_inp (pbase + linestatus) & txreadybit)
  584.            {
  585.            break;
  586.            }
  587.        tsk_nop ();
  588.        }
  589.  
  590.    tsk_nop ();
  591.    tsk_cli ();
  592.    tsk_outp (pbase + intenable, intdata);
  593.    tsk_nop ();
  594.    tsk_outp (pbase + intenable, intdata);
  595.    tsk_sti ();
  596.  
  597. }
  598.  
  599.  
  600. commport::~commport ()
  601.    {
  602.    intprocptr far *intptr;
  603.    int pbase, i, inta;
  604.    portptr portp;
  605.    commptr curr, last;
  606.  
  607.    pbase = port_base;
  608.    portp = port;
  609.  
  610.    last = NULL;
  611.    curr = irq_array [portp->irq];
  612.    while (curr != this && curr != NULL)
  613.       {
  614.       last = curr;
  615.       curr = curr->next;
  616.       }
  617.    if (curr == NULL)
  618.       return;
  619.  
  620.    tsk_outp (pbase + intenable, 0);
  621.    tsk_cli ();
  622.    if (last == NULL)
  623.       irq_array [portp->irq] = next;
  624.    else
  625.       last->next = next;
  626.    tsk_sti ();
  627.  
  628.    inta = (portp->irq > 7) ? inta11 : inta01;
  629.  
  630.    // ???? this was an input param, now a member that is set in constructor
  631.    if (restore)
  632.       {
  633.       tsk_outp (pbase + modemcontrol, save_mcon);
  634.       tsk_nop ();
  635.       tsk_outp (pbase + linecontrol, save_lcon | 0x80);
  636.       tsk_nop ();
  637.       tsk_outp (pbase + baudreg_dll, save_bd1);
  638.       tsk_nop ();
  639.       tsk_outp (pbase + baudreg_dlm, save_bd2);
  640.       tsk_nop ();
  641.       tsk_outp (pbase + linecontrol, save_lcon);
  642.       tsk_nop ();
  643.       if (irq_array [portp->irq] == NULL)
  644.          {
  645.          tsk_cli ();
  646.          tsk_outp (pbase + intenable, save_inten);
  647.          i = tsk_inp (inta) & ~irqbit;
  648.          tsk_nop ();
  649.          tsk_outp (inta, i | save_irq);
  650.          }
  651.       }
  652.    else if (irq_array [portp->irq] == NULL)
  653.       {
  654.       tsk_cli ();
  655.       i = tsk_inp (inta) | irqbit;
  656.       tsk_nop ();
  657.       tsk_outp (inta, i);
  658.       }
  659.  
  660.    if (irq_array [portp->irq] == NULL)
  661.       {
  662.       tsk_cli ();
  663.       intptr = (intprocptr far *)MK_FP (0, civect * 4);
  664.       *intptr = (intprocptr)savvect;
  665.       }
  666.    tsk_sti ();
  667.  
  668.    portp->sio = NULL;
  669.    }
  670.  
  671.  
  672. /*-------------------------------------------------------------------------*/
  673.  
  674. /*
  675.    void change_rts (int on)
  676. */
  677.  
  678. void far commport::change_rts (int on)
  679. {
  680.    cmodcontrol = (cmodcontrol & ~RTS) | ((on) ? RTS : 0);
  681.    tsk_outp (port_base + modemcontrol, cmodcontrol);
  682. }
  683.  
  684. /*
  685.    void change_dtr (int on)
  686. */
  687.  
  688. void far commport::change_dtr (int on)
  689. {
  690.    cmodcontrol = (cmodcontrol & ~DTR) | ((on) ? DTR : 0);
  691.    tsk_outp (port_base + modemcontrol, cmodcontrol);
  692. }
  693.  
  694.  
  695. /*
  696.    void far change_baud (int rate)
  697. */
  698.  
  699. void far commport::change_baud (long rate)
  700. {
  701.    int i;
  702.  
  703.    for (i = 0; baud_table [i]; i += 2)
  704.       if (baud_table [i] == rate)
  705.          break;
  706.    if (!(i = (int)baud_table [i + 1]))
  707.       return;
  708.  
  709.    tsk_outp (port_base + linecontrol, clcontrol | (byte)0x80);
  710.    tsk_nop ();
  711.    tsk_outp (port_base + baudreg_dll, (byte)i);
  712.    tsk_nop ();
  713.    tsk_outp (port_base + baudreg_dlm, (byte)(i >> 8));
  714.    tsk_nop ();
  715.    tsk_outp (port_base + linecontrol, clcontrol);
  716. }
  717.  
  718.  
  719. void far commport::change_parity (int par)
  720. {
  721.    clcontrol = (clcontrol & 0xc7) | par;
  722.    tsk_outp (port_base + linecontrol, clcontrol);
  723. }
  724.  
  725.  
  726. void far commport::change_wordlength (int len)
  727. {
  728.    int i;
  729.  
  730.    switch (len)
  731.       {
  732.       case 5:  i = 0x00; break;
  733.       case 6:  i = 0x01; break;
  734.       case 7:  i = 0x02; break;
  735.       case 8:  i = 0x03; break;
  736.       default: return;
  737.       }
  738.    clcontrol = (clcontrol & 0xfc) | i;
  739.    tsk_outp (port_base + linecontrol, clcontrol);
  740. }
  741.  
  742.  
  743. void far commport::change_stopbits (int n)
  744. {
  745.    int i;
  746.  
  747.    switch (n)
  748.       {
  749.       case 1:  i = 0x00; break;
  750.       case 2:  i = 0x04; break;
  751.       default: return;
  752.       }
  753.    clcontrol = (clcontrol & 0xfb) | i;
  754.    tsk_outp (port_base + linecontrol, clcontrol);
  755. }
  756.  
  757.  
  758. void far commport::watch_modem (byte flags)
  759. {
  760.    modem_flags = flags & (CTS | DSR | RI | CD);
  761. }
  762.  
  763.  
  764. void far commport::protocol (int prot, word offthresh, word onthresh)
  765. {
  766.    byte old;
  767.    
  768.    old = flags;
  769.    flags = (byte)prot;
  770.    if (prot)
  771.       {
  772.       if (!offthresh)
  773.          offthresh = 10;
  774.       xoff_threshold = offthresh;
  775.       if (onthresh <= offthresh)
  776.          onthresh = offthresh + 10;
  777.       xon_threshold = onthresh;
  778.       }
  779.  
  780.    if ((old & RTSCTS) != ((byte)prot & RTSCTS))
  781.       {
  782.       chng_rts (1);
  783.       modem_flags = (modem_flags & ~CTS) |
  784.                          ((prot & RTSCTS) ? CTS : 0);
  785.       }
  786.  
  787.    if (!(prot & XONXOFF))
  788.       {
  789.       if (r_xoff)
  790.          r_xoff = -2;
  791.       t_xoff = 0;
  792.       }
  793.  
  794.    if (!xmit_pending)
  795.       transmit_ready ();
  796. }
  797.  
  798.  
  799. /*-------------------------------------------------------------------------*/
  800.  
  801.  
  802. int far commport::send (byte ch, dword timeout)
  803. {
  804.    int res;
  805.  
  806.    if ((res = xmit_pipe.write_pipe (ch, timeout)) < 0)
  807.       return res;
  808.    tsk_cli ();
  809.    if (!xmit_pending)
  810.       transmit_ready ();
  811.    tsk_sti ();
  812.    return 0;
  813. }
  814.  
  815.  
  816. int far commport::receive (dword timeout)
  817. {
  818.    int res;
  819.    
  820.    if ((res = (int)rcv_pipe.read_wpipe (timeout)) < 0)
  821.       return res;
  822.  
  823.    if (!flags)
  824.       return res;
  825.  
  826.    if (rcv_pipe.wpipe_free () > xon_threshold)
  827.       {
  828.       tsk_cli ();
  829.       if (r_xoff)
  830.          {
  831.          r_xoff = -2;
  832.          if (!xmit_pending)
  833.             transmit_ready ();
  834.          }
  835.       tsk_sti ();
  836.  
  837.       if (rtsoff)
  838.          chng_rts (1);
  839.       }
  840.    return res;
  841. }
  842.  
  843.  
  844. int far commport::rcv_overrun (void)
  845. {
  846.    int res;
  847.  
  848.    res = overrun;
  849.    overrun = 0;
  850.    return res;
  851. }
  852.  
  853.  
  854. int far commport::check (void)
  855. {
  856.    return rcv_pipe.check_wpipe ();
  857. }
  858.  
  859.  
  860. int far commport::modem_status (void)
  861. {
  862.    return modstat;
  863. }
  864.  
  865.  
  866. int far commport::complete (void)
  867. {
  868.    return (xmit_pipe.check_pipe () == -1);
  869. }
  870.  
  871.  
  872. int far commport::wait_complete (dword timeout)
  873. {
  874.    return xmit_pipe.wait_pipe_empty (timeout);
  875. }
  876.  
  877.  
  878. void far commport::flush_receive (void)
  879. {
  880.     rcv_pipe.flush_wpipe ();
  881. }
  882.